package spindles.gwt.client;

import java.util.List;

import spindles.gwt.client.TableData.Row;
import spindles.gwt.shared.Const;
import spindles.gwt.shared.EpochDTO;
import spindles.gwt.shared.SleepDTO;
import spindles.gwt.shared.SpindleDTO;

import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

public class SpindleDetectionPanel extends RightPanel implements Subscriber{
	
	private String masterTableName = Const.PERSON_TABLENAME;
	
	private Row selectedRow;	
	
	private String title;	
	
	private List softSpindles;
	private List hardSpindles;
	
	public SpindleDetectionPanel(){	
		setPersonsTable();
		init(new Toolbar(Const.PERSONS_SLEEPS_TITLE), 
				detailsTable, 
				new SimplePanel());
	}	
	
	public class MasterDataPanel extends Composite{
		public static final int VISIBLE_LENGTH = 30;		
		
		public static final String MENU_TITLE = 
			"Tools...<span style=font-size:12px>&#9660;</span>";
		
		private Toolbar toolbar;
		
		public MasterDataPanel(String title){
			toolbar = new Toolbar(title);
			
			VerticalPanel panel = new VerticalPanel();
			if(masterTableName.equals(Const.PERSON_TABLENAME)){
				panel = personPanel();
			}else if(masterTableName.equals(Const.SLEEP_TABLENAME)){
				panel = sleepPanel();
			}else if(masterTableName.equals(Const.PART_TABLENAME)){
				panel = sleepPartPanel();
			}else{
				panel = epochPanel();
			}
			initWidget(panel);
		}		
		
		public Toolbar getToolbar(){
			return toolbar;
		}
		
		private Command createExportCommand(final int type){
			return new Command() {
		    	public void execute() {
		    		Callback callback = new Callback(){
						public void execute(Object result) {
							Spindles.showInfoDialog("Export", "Exported data at: " + (String)result);							
						}						
					};
		    		
					ServerGateway.getExportPath(type, 
							Long.parseLong(Registry.getMasterRecord().getValue(0)),
							Registry.withSoftCriterion(), 
							Spindles.createCallBack(callback));	
				}
			};
		}
		
		private VerticalPanel personPanel(){	
			MenuBar actions = new MenuBar(true);
			
			actions.addItem("Spindles Report", createSpindlesReportCommand(Const.PERSON_LEVEL));
			
			MenuBar exportMenu = new MenuBar(true);
			exportMenu.addItem("ASCII", createExportCommand(Const.ASCII_EXPORT));			
			exportMenu.addItem("Filtered", createExportCommand(Const.FILTERED_EXPORT));			
			exportMenu.addItem("PNG", createExportCommand(Const.PNG_EXPORT));			
			exportMenu.addItem("PostScript", createExportCommand(Const.PS_EXPORT));
			exportMenu.addItem("Mat", createExportCommand(Const.MAT_EXPORT));		    
		    
		    actions.addItem("Export", exportMenu);
		    		
			createMenuBar(Const.PERSON_LEVEL, actions);
			
			VerticalPanel outer = new VerticalPanel();		
				
			outer.add(createRowPanel(createLabel(selectedRow.getFieldName(0)), 
					createTextBox(selectedRow.getValue(0), false)));			
			outer.add(createRowPanel(createLabel(selectedRow.getFieldName(1)), 
					createTextBox(selectedRow.getValue(1))));
			outer.add(createRowPanel(createLabel(selectedRow.getFieldName(2)), 
					createTextBox(selectedRow.getValue(2))));
			outer.add(createRowPanel(createLabel(selectedRow.getFieldName(3)), 
					createTextArea(selectedRow.getValue(3))));
			
			return outer;
		}
		
		private VerticalPanel sleepPanel(){			
			
			createMenuBar(Const.SLEEP_LEVEL);
			
			VerticalPanel outer = new VerticalPanel();									
			
			outer.add(createRowPanel(createLabel(selectedRow.getFieldName(0)), 
					createTextBox(selectedRow.getValue(0), false)));
			outer.add(createRowPanel(createLabel(selectedRow.getFieldName(1)), 
					createTextBox(selectedRow.getValue(1))));
			outer.add(createRowPanel(createLabel(selectedRow.getFieldName(2)), 
					createTextBox(selectedRow.getValue(2))));
			return outer;
		}
		
		private CheckBox createCheckBox(ClickListener listener){
			CheckBox cb = new CheckBox("Soft Criterion");
			cb.setChecked(true);
			cb.setStyleName("spindles-CheckBox");
			
			cb.addClickListener(listener);
			
			return cb;
		}
		
		private CheckBox createCheckBox(){
			CheckBox criterionCB = createCheckBox(new ClickListener() {
				public void onClick(Widget sender) {
					boolean soft = ((CheckBox) sender).isChecked();
					Registry.setCriterion(soft);
				}
			});
			
			return criterionCB;
		}
		
		private Command createSpindlesReportCommand(final String level){
			return new Command() {
				public void execute() {					
					Callback callback = new Callback(){
						public void execute(Object result) {
							String fileURL = (String) result;
							Spindles.openWindow(fileURL);							
						}						
					};
					
					ServerGateway.getExportURL(level, 
							Long.parseLong(Registry.getMasterRecord().getValue(0)), 
							Registry.withSoftCriterion(), 
							Spindles.createCallBack(callback));
				}
			};
		}
		
		private MenuBar createMenuBar(String level, MenuBar actions){
			Registry.setCriterion(true);		        
		    
		    MenuBar menu = new MenuBar();
		    menu.addItem(MENU_TITLE, true, actions);			
			
			toolbar.add(menu);
			toolbar.add(createCheckBox());
			
			return menu;
		}
		
		private MenuBar createMenuBar(String level){			
		    MenuBar actions = new MenuBar(true);  
		    
		    actions.addItem("Spindles Report", createSpindlesReportCommand(level));	    
		    
		    return createMenuBar(level, actions);
		}
		
		private VerticalPanel sleepPartPanel(){			
		    MenuBar actions = new MenuBar(true);		    
		    actions.addItem("Spindles Indications Plot", new Command() {
		    	public void execute() {
		    		Spindles.openWindow(ServerGateway.getPlotURL()
							+ "?plotType=density&partID="
							+ Registry.getMasterRecord().getValue(0) + "&soft="
							+ Registry.withSoftCriterion());								
				}
			});		    
		    actions.addItem("Spindles Report", createSpindlesReportCommand(Const.PART_LEVEL));	    
		    
		    createMenuBar(Const.PART_LEVEL, actions);
			
			
			VerticalPanel outer = new VerticalPanel();									
			
			outer.add(createRowPanel(createLabel(selectedRow.getFieldName(0)), 
					createTextBox(selectedRow.getValue(0), false)));
			outer.add(createRowPanel(createLabel(selectedRow.getFieldName(1)), 
					createTextBox(selectedRow.getValue(1))));
			outer.add(createRowPanel(createLabel(selectedRow.getFieldName(2)), 
					createTextBox(selectedRow.getValue(2))));
			outer.add(createRowPanel(createLabel(selectedRow.getFieldName(3)), 
					createTextBox(selectedRow.getValue(3))));
			return outer;
		}
		
		private VerticalPanel epochPanel(){			
			Registry.setCriterion(true);
		    MenuBar actions = new MenuBar(true);
		    actions.addItem("Epoch Plot", new Command(){
				public void execute() {					
					Spindles.openWindow(ServerGateway.getPlotURL()
							+ "?plotType=epoch&epochID="
							+ Registry.getMasterRecord().getValue(0) + "&soft="
							+ Registry.withSoftCriterion() + "&raw="
							+ Registry.showRawEEG());			
				}		    	
		    });		    
		    actions.addItem("Spindles Report", createSpindlesReportCommand(Const.EPOCH_LEVEL));
		    
		    // Make a new menu bar, adding a few cascading menus to it.
		    MenuBar menu = new MenuBar();
		    menu.addItem(MENU_TITLE, true, actions);		
			
			CheckBox criterionCB = createCheckBox(new ClickListener() {
				public void onClick(Widget sender) {
					boolean soft = ((CheckBox) sender).isChecked();
					if (soft) {
						detailsTable.setTableData(createTableData(softSpindles,
								Const.SPINDLE_TABLENAME, Const.SPINDLE_FIELDS));
					} else {
						detailsTable.setTableData(createTableData(hardSpindles,
								Const.SPINDLE_TABLENAME, Const.SPINDLE_FIELDS));
					}

					Registry.setCriterion(soft);
				}
			});
			
			toolbar.add(menu);
			toolbar.add(criterionCB);			
			
			VerticalPanel outer = new VerticalPanel();									
			
			outer.add(createRowPanel(createLabel(selectedRow.getFieldName(0)), 
					createTextBox(selectedRow.getValue(0), false)));
			outer.add(createRowPanel(createLabel(selectedRow.getFieldName(1)), 
					createTextBox(selectedRow.getValue(1))));
			outer.add(createRowPanel(createLabel(selectedRow.getFieldName(2)), 
					createTextBox(selectedRow.getValue(2))));
			outer.add(createRowPanel(createLabel(selectedRow.getFieldName(3)), 
					createTextBox(selectedRow.getValue(3))));
			outer.add(createRowPanel(createLabel(selectedRow.getFieldName(4)), 
					createTextBox(selectedRow.getValue(4))));			
			
			return outer;
		}
		
		private HorizontalPanel createRowPanel(Widget first, Widget second){
			HorizontalPanel hp = new HorizontalPanel();
			hp.setSpacing(5);
			hp.add(first);
			hp.add(second);
			return hp;
		}
		
		private TextArea createTextArea(String text){
			TextArea ta = new TextArea();
			ta.setText(text);
			ta.setCharacterWidth(50);	
			ta.setVisibleLines(4);
			return ta;
		}
		
		private TextBox createTextBox(String text, boolean enabled){
			TextBox tb = new TextBox();
			tb.setText(text);
			
			if(text.length() > VISIBLE_LENGTH){
				tb.setVisibleLength(text.length());
			} else{
				tb.setVisibleLength(VISIBLE_LENGTH);
			}
			
			tb.setEnabled(enabled);
			return tb;
		}
		
		private TextBox createTextBox(String text){
			return createTextBox(text, true);
		}
		
		private Label createLabel(String text){
			text += ": ";
			Label l = new Label(text);
			l.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
			l.setWidth("150px");
			return l;
		}
		
		
	}
	
	private void showSpindleRawData(Row row){
		Callback callback = new Callback(){
			public void execute(Object result) {
				String fileURL = (String) result;
				Spindles.openWindow(fileURL);							
			}						
		};
		
		ServerGateway.getExportURL(Long.parseLong(Registry.getMasterRecord()
				.getValue(0)), (SpindleDTO) row.getDTO(), row.getRowPosition(),
				Spindles.createCallBack(callback));		
	}

	public void update(Object o) {
		if(((Row)o).getTableName().equals(Const.SPINDLE_TABLENAME)){
			showSpindleRawData((Row)o);			
			return;
		}
		selectedRow = (Row)o;
		Registry.setMasterRecord(selectedRow);
		masterTableName = selectedRow.getTableName();
		
		setTitleAndDetailsData(selectedRow);
		
		MasterDataPanel mdp = new MasterDataPanel(title);
		replaceTopWidget(mdp.getToolbar());
		replaceSplitTopWidget(mdp);		
		replaceSplitBottomWidget(detailsTable);
	}
	
	private void setTitleAndDetailsData(Row row){
		if(masterTableName.equals(Const.PERSON_TABLENAME)){
			setSleepsTable(row.getValue(0));
			title = Const.PERSONS_SLEEPS_TITLE;
		}else if(masterTableName.equals(Const.SLEEP_TABLENAME)){
			setPartsTable(row.getValue(0));
			title = Const.SLEEPS_PARTS_TITLE;
		}else if(masterTableName.equals(Const.PART_TABLENAME)){
			setEpochsTable(row.getValue(0));
			title = Const.PARTS_EPOCHS_TITLE;
		}else{
			setSpindlesTable(row.getValue(0));
			title = Const.EPOCHS_TITLE;
		}		
	}
	
	private void setSpindlesTable(String epochID){
		EpochDTO parentDTO = (EpochDTO)Registry.getDTO(epochID);
		softSpindles = parentDTO.getSoftSpindles();
		hardSpindles = parentDTO.getHardSpindles();
		
		setDetailsTable(Const.SPINDLE_TABLENAME, Const.SPINDLE_FIELDS, softSpindles);
	}
	
	private void setEpochsTable(String sleepPartID){
		AsyncCallback c = setDetailsTable(Const.EPOCH_TABLENAME, 
				new String[] { "ID", "Start", "End", 
								"Spindles with Soft Criterion", 
								"Spindles with Hard Criterion" });		
		ServerGateway.getEpochs(Long.parseLong(sleepPartID), c);
	}
	
	private void setPartsTable(String sleepID){
		SleepDTO parentDTO = (SleepDTO)Registry.getDTO(sleepID);
		
		setDetailsTable(Const.PART_TABLENAME,
				new String[] { "ID", "Start", "End", "Channel" },
				parentDTO.getSleepParts());
	}
	
	private void setSleepsTable(String personID){		
		AsyncCallback c = setDetailsTable(Const.SLEEP_TABLENAME, 
				new String[] { "ID", "Date", "Sampling Rate (Hz)" });		
		ServerGateway.getSleeps(Long.parseLong(personID), c);		
	}
	
	private void setPersonsTable(){		
		AsyncCallback c = setDetailsTable(Const.PERSON_TABLENAME, 
				new String[]{"ID", "Firstname", "Lastname", "Comments"});		
		ServerGateway.getPersons(c);		
	}	
	

}
